//////////////////////////////////////////////////////////////////////////
//
// GAM203
// Quad
// Quad.cpp
// 
// Grant Johnson
// Qantm College
// 27/10/2010
//
//////////////////////////////////////////////////////////////////////////

#include "Quad.h"
#include <stdio.h>
#include <d3dx9.h>
#include "RenderParams.h"
#include "Shadermgr.h"
#include "Shader.h"
#include "Renderer.h"

Quad::Quad()
: m_pTex(NULL)
, m_vertCount(5)
, m_indexCount(4)
{
	m_pTexFilename = new char[256];
}

Quad::~Quad()
{
	//Cleanup
	if (m_pTex)
	{
		m_pTex->Release();
		m_pTex = NULL;
	}
	if(m_pTexFilename)
	{
		delete m_pTexFilename;
		m_pTexFilename = NULL;
	}
}

bool Quad::CreateObject(IDirect3DDevice9* a_pDevice, char* a_pTexFileName)
{
	//No device was given
	if (!a_pDevice)
	{
		return false;
	}

	//Copy over the filename for the texture, sprintf_s ensures it's not NULL
	sprintf_s(m_pTexFilename, 256, "%s", a_pTexFileName);

	HRESULT result;

	//Create a texture
	result = D3DXCreateTextureFromFile(a_pDevice, m_pTexFilename, &m_pTex);
	if (FAILED(result))
	{
		return false;
	}

	D3DVERTEXELEMENT9 elements[] = 
	{
		{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
		{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
		{0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
		D3DDECL_END()
	};

	if(FAILED(D3DXCreateMesh(2, m_vertCount, D3DXMESH_MANAGED, elements, a_pDevice, &m_pMesh)))
		return false;

	//Create an array of vertex data on the stack
	m_pVertData = new VertexData[m_vertCount];

	const float QUAD_HALF_SIZE = 1.0f;
	m_pVertData[0].pos = D3DXVECTOR3(-QUAD_HALF_SIZE,  QUAD_HALF_SIZE, 0);
	m_pVertData[1].pos = D3DXVECTOR3( QUAD_HALF_SIZE,  QUAD_HALF_SIZE, 0);
	m_pVertData[2].pos = D3DXVECTOR3(-QUAD_HALF_SIZE, -QUAD_HALF_SIZE, 0);
	m_pVertData[3].pos = D3DXVECTOR3( QUAD_HALF_SIZE, -QUAD_HALF_SIZE, 0);

	m_pVertData[0].normal = D3DXVECTOR3(0, 1, 0);
	m_pVertData[1].normal = D3DXVECTOR3(0, 1, 0);
	m_pVertData[2].normal = D3DXVECTOR3(0, 1, 0);
	m_pVertData[3].normal = D3DXVECTOR3(0, 1, 0);

	m_pVertData[0].u = 0.0f; m_pVertData[0].v = 0.0f;
	m_pVertData[1].u = 1.0f; m_pVertData[1].v = 0.0f;
	m_pVertData[2].u = 0.0f; m_pVertData[2].v = 1.0f;
	m_pVertData[3].u = 1.0f; m_pVertData[3].v = 1.0f;

	//Create an array of index data on the stack
	m_pIndexData = new unsigned short[m_indexCount];
	//Only need 4 indices if we draw the quad as a triangle STRIP, not a triangle LIST
	m_pIndexData[0] = 0;
	m_pIndexData[1] = 2;
	m_pIndexData[2] = 1;
	m_pIndexData[3] = 3;

	//Setup the material
	m_mtl.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	m_mtl.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	m_mtl.Emissive = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	m_mtl.Specular = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
	m_mtl.Power = 0.1f;

	//Copy vertex data into vertex buffer
	void* pLockedData = NULL;
	if(FAILED(m_pMesh->LockVertexBuffer(0, &pLockedData)))
		return false;
	memcpy(pLockedData, m_pVertData, sizeof(VertexData) * m_vertCount);
	if(FAILED(m_pMesh->UnlockVertexBuffer()))
		return false;
	pLockedData = NULL;

	//Copy index data into index buffer
	if(FAILED(m_pMesh->LockIndexBuffer(0, &pLockedData)))
		return false;
	memcpy(pLockedData, m_pIndexData, sizeof(unsigned short) * m_indexCount);
	if(FAILED(m_pMesh->UnlockIndexBuffer()))
		return false;
	pLockedData = NULL;

	return true;
}

void Quad::Render(float a_dt, IDirect3DDevice9* a_pDevice, const RenderParams& a_renderParams)
{
	if (a_pDevice && m_pMesh)
	{
		const char* SHADER_NAME = "BillboardShader";
		Shader* pShader = ShaderMgr::GetInstance().Find(SHADER_NAME);
		if(pShader)
		{
			ID3DXEffect* pEffect = pShader->GetEffect();
			if(pEffect)
			{
				pEffect->SetTechnique("RenderTex1");

				//Set texture global variable
				pEffect->SetTexture("g_texture", m_pTex);

				pEffect->SetValue("g_eyePos", Renderer::GetInstance().GetActiveCamera()->GetEyePos(), sizeof(D3DXVECTOR3));
				
				//Set matrix global variables
				//Calculate a combined world*view*proj matrix for the vertex shader
				D3DXMATRIX worldViewProj = m_worldMatrix*a_renderParams.GetViewMatrix()*a_renderParams.GetProjMatrix();
				pEffect->SetMatrix("g_worldViewProj", &worldViewProj);
				pEffect->SetMatrix("g_worldMat", &m_worldMatrix);

				//Render with shader
				UINT passCount = 0;
				if(pEffect->Begin(&passCount, 0) == D3D_OK)
				{
					for(UINT passIndex = 0; passIndex < passCount; ++passIndex)
					{		
						if(pEffect->BeginPass(passIndex) == D3D_OK)
						{
							//Draw the cube
							//a_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
							a_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
							if(FAILED(m_pMesh->DrawSubset(0)))
							{
								return;
							}

							pEffect->EndPass();
						}
					}
					pEffect->End();
				}
			}
		}
	}
}